from pydantic import BaseModel, Field, field_validator
from typing import Dict, List, Optional, Union


# 定义预期响应
class ExpectedResponse(BaseModel):
    status_code: int = Field(..., description="期望的HTTP状态码")
    response: List[Dict[str, Union[str, int]]] = Field(
        default_factory=list,
        description="期望的响应字段列表，每个字段为字典格式，如{'code': 0}"
    )


# 定义测试参数, 这是单接口测试用例
class TestCase(BaseModel):
    feature: str = Field(..., description="allure装饰的feature：你需要定义功能模块名称")
    description: str = Field(..., description="allure装饰的description：你需要提供测试用例的详细描述")
    story: str = Field(..., description="allure装饰的story: 你需要定义用户故事或接口功能点")
    title: str = Field(..., description="allure装饰的title: 你需要定义测试用例标题")
    severity: str = Field(...,
                          description="allure装饰的severity: 你需要定义测试用例优先级(BLOCKER, CRITICAL, NORMAL, MINOR, TRIVIAL)")
    name: str = Field(...,
                      description="这是pytest的测试用例的名称， 你需要定义这个测试用例的函数名称， 如：test_01_method_name, test_02_method_name, "
                                  "这里必须是test_开头， method_nameb必须是英文")

    url: str = Field(..., description="请求地址, 这里的地址是接口的路径，不是域名")
    method: str = Field(..., description="HTTP 请求方法")
    headers: Optional[Dict[str, str]] = Field(default={'Content-Type': 'application/json'},
                                              description="请求头部信息, 如果参数有值，这里就填写对应的值，如果没有写，请求头则使用默认值， 一定要有默认的值，不能为空")
    request: str = Field(...,
                         description="接口请求的传参方式， get则默认为paramsc传参，post则为json传参，如果接口文档中有request说明，则使用接口文档中的request传参方式")
    # 这里的传参方式是是自己定义的
    params: Dict[str, object] = Field(..., description="请求参数")
    # 断言还没做好，但是不影响生成测试用例
    # expected: Dict[str, object] = Field(...,
    #                                     description="预期返回结果，目前只需要包含状态码status_code，如果接口测试文档信息中，"
    #                                                 "给了对应的返回值，断言则根据响应信息新增为：响应体结构断言response_schema")
    # 扩展expected字段
    expected: ExpectedResponse = Field(
        ...,
        description="预期返回结果，包含状态码、code、message等字段，"
                    "如果接口测试文档信息中，给了对应的返回值response, 则根据response，进行断言"
                    "如 response：{'code': 13440, 'msg': 'invalid parameter', 'data': None}"
    )

    @field_validator('method')
    def validate_http_method(cls, v):
        valid_methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
        if v.upper() not in valid_methods:
            raise ValueError(f'Invalid HTTP method: {v}')
        return v

    # @field_validator('params', 'expected')
    @field_validator('params')
    def validate_dict(cls, v):
        if not isinstance(v, dict):
            raise ValueError('Expected a dictionary')
        return v

    @field_validator('severity')
    def validate_severity(cls, v):
        valid_levels = ['BLOCKER', 'CRITICAL', 'NORMAL', 'MINOR', 'TRIVIAL']
        if v.upper() not in valid_levels:
            raise ValueError(f'Invalid severity level: {v}')
        return v.upper()
